package com.wise.eventserver.outsider.engine.service.impl;
import com.antlang.dao.AntDao;
import com.antlang.enums.VariableTypeEnum;
import com.antlang.factory.AntFactory;
import com.antlang.util.ANT;
import com.outsider.enums.DataTypeEnum;
import com.outsider.reflect.IRequestData;
import com.outsider.strongdata.IDate;
import com.outsider.strongdata.IObject;
import com.outsider.strongdata.IString;
import com.outsider.util.ILogger;
import com.outsider.util.IValid;
import com.wise.eventserver.outsider.engine.service.InstructionEngineService;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.Map;

import static com.antlang.object.AntKeyword._BOOL;
import static com.antlang.object.AntKeyword._ENTITY;
import static com.antlang.object.AntKeyword._THIS;
import static com.wise.eventserver.outsider.standard.InstructionAspect.*;

@Service("instructionEngineService")
public class InstructionEngineServiceImpl implements InstructionEngineService {

    private static boolean isSingleRunningAnt = false;
    private static boolean isStartAutoLoad = false;
    // 暂停接口执行
    private static boolean isStartAnt = false;

    private static final int MAX_REMARK_SIZE = 1000;

    @Resource
    private IValid validUtil;
    @Resource
    private IRequestData requestData;
    @Resource
    private AntDao outsiderDao;

    private ILogger logger = null;

    public boolean checkSingleAntRunning () {
        return isSingleRunningAnt;
    }

    /**
     * 指令前置、后置处理，接口实现
     */
    @Override
    public boolean handleMacroinstructionAspect (String id, String aspectType) {
        boolean isTrue = false;

        if (isStartAnt && !checkSingleAntRunning()) {
            try {
                isSingleRunningAnt = true;
                //ActualInstructionEntity actualInstruction = actualInstructionDao.getEntity(id);
                //isTrue = handleInstructionAspect(actualInstruction, aspectType);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            } finally {
                isSingleRunningAnt = false;
            }
        } else {
            logger.debug("WARNING KEYWORD " + id + " NOT RUN handleMacroinstructionAspect ");
        }

        return isTrue;
    }

    /**
     * 指令前置、后置处理，接口实现
     */
    @Override
    public boolean handleMachineInstructionAspect (String id, String aspectType) {
        boolean isTrue = false;
        if (isStartAnt && !checkSingleAntRunning()) {
            try {
                isSingleRunningAnt = true;
                // ActualInstructionDetailEntity detail = actualInstructionDetailDao.getEntity(id);
                // isTrue = handleInstructionAspect(detail, aspectType);
            } catch (Exception e) {
                e.printStackTrace();
                logger.error(e.getMessage());
            } finally {
                isSingleRunningAnt = false;
            }
        } else {
            logger.debug("WARNING KEYWORD " + id + " NOT RUN handleMachineInstructionAspect ");
        }
        return isTrue;
    }

    @Override
    public void testAnt(Object o) {
        String code = "\n" +
                "FUNCTION\n" +
                //"支持的写法\n" +
                //"STRING [empty] EQUAL \"\" \n" +
                //"SET [empty] EQUAL TEST \n" +
                //"SET [empty] EQUAL \"\" \n" +
                //"SET [empty] EQUAL [null] \n" +

                "DATETIME [now] EQUALNEW \n" +
                //"SET [this]->str EQUAL test \n" +
                //"SET [this]->str EQUAL \"\" \n" +

                //"SET [now] EQUAL [null] \n" +
                //"INT [day] EQUALDAY [now] \n" +
                "PRINT [this]->deviceName \n" +
                "BYTEARRAY [ba] \n" +
                "SET [ba] EQUAL 0201000500060333000000 \n" +

                "BYTE [b] \n" +
                "STRING [hexstr] \n" +
                "STRING [hexArray] \n" +
                "INT [i] EQUAL -1 \n" +
                "INT [size] EQUALSIZE [ba] \n" +
                "SUBNUM 1 EQUAL [size] \n" +

                "LOOP [i] LT [size]\n" +

                "ADDNUM 1 EQUAL [i] \n" +
                "SET [b] EQUALGET [ba]->[i] \n" +
                "SET [hexstr] EQUALHEX [b] \n" +
                "ADDEND [hexstr] EQUAL [hexArray] \n" +
                "PRINT [hexstr] \n" +
                "PRINT [hexArray] \n" +

                "END LOOP\n" +

                "SET [now] EQUALNEW \n" +
                "PRINT [now] \n" +
                "SET [size] EQUAL 900 \n" +
                "SET [i] EQUAL 0 \n" +

                "LOOP [i] LT [size]\n" +
                "ADDNUM 1 EQUAL [i] \n" +
                //"PRINT [i] \n" +

                "SET [this]->deviceName EQUALSTRING [i] \n" +
                "SAVEORUPDATE [this] \n" +
                //"PRINT [this]->deviceName \n" +

                "END LOOP\n" +

                "SET [now] EQUALNEW \n" +
                "PRINT [now] \n" +
                //"SET [b] EQUAL 31 \n" +
                //"SET [b] EQUAL 0x31 \n" +
                //"SUBNUM 12 EQUAL [b] \n" +
                //"SUBNUM 0x12 EQUAL [b] \n" +
                //"SET [b] SUBNUM 13 \n" +
                //"SET [b] SUBNUM 0x13 \n" +
                //"IF [b] EQ 31 \n" +
                //"PRINT 等于 31 \n" +
                //"ELSEIF [b] EQ 0x31 \n" +
                //"PRINT 等于49 \n" +
                //"END IF \n" +
                //"INT [size] EQUALSIZE [testList]\n" +
                //"INT [one] EQUAL 0 \n " +

                //"ADDNUM 1 EQUAL [one] \n" +
                //"SET [one] ADDNUM 1 \n" +
                //"DOUBLE [two] EQUAL 0  \n" +
                //"ADDNUM 1 EQUAL [two] \n" +
                //"SET [two] ADDNUM 1 \n" +

                //"SUBNUM 1 EQUAL [one] \n" +
                //"SET [one] SUBNUM 1 \n" +
                //"DOUBLE [two] \n" +
                //"SUBNUM 1 EQUAL [two] \n" +
                //"SET [two] SUBNUM 1 \n" +
                //"STRING [hex] EQUALHEX [b] \n" +
                //"STRING [testH] \n" +
                //"SET [testH] EQUALHEX [b] \n" +
                //"INT [i] EQUAL 0 \n" +
                "\n" +
//                      "LOOP [i] LT [size]\n" +
//                      "SET [one] EQUALGET [testList]->[i]\n" +
//                      "\n" +
//                      "IF [i] EQ 1\n" +
//                      "THEN [i] ADDNUM 1\n" +
//                      "THEN CONTINUE\n" +
//                      "END IF\n" +
//                      "\n" +
//                      "IF [i] GE 3\n" +
//                      "THEN BREAK\n" +
//                      "END IF\n" +
//                      "\n" +
//                      "ADDNUM 1 EQUAL [i]\n" +
//                      "" +
//                      "END LOOP\n" +

//                      "ADDNUM 1 EQUAL [i]\n" +
//                      "\n" +
//                      "IF [i] LT [size]\n" +
//                      "THEN [i] ADDNUM 1\n" +
//                      "END IF\n" +
//                      "\n" +
//                      "IF [i] LT [size]\n" +
//                      "THEN [i] ADDNUM 3\n" +
//                      "END IF\n" +
//                      "\n" +
//                      "IF [i] GT [size]\n" +
//                      "THEN [i] EQUAL 0\n" +
//                      "END IF" +
//                      "" +
                "END FUNCTION\n";
        ANT ant = initAnt();
        Map<String, Object[]> variables = new HashMap<>();

        Object[] _this = new Object[2];
        _this[0] = "ENTITY";
        _this[1] = o;
        variables.put("[this]", _this);

        ant.setVariables(variables);

        boolean isTrue = tryExecuteAnt(ant, code);

    }

    public ANT initAnt () {
        ANT ant = AntFactory.requestVariable(VariableTypeEnum.ANT);
        // 初始化ANT 的参数
        ant.setAntDao(outsiderDao);
        return ant;
    }

    /**
     * 当为true时，只能执行一次；
     * 当为false时，会一直执行直到变为true
     */
    public synchronized boolean handleInstructionAspect (Object o, String aspectType) throws Exception {
        Boolean isTrue = false;

        IString remark = requestData.newInstance(DataTypeEnum.STRING);
        IDate now = requestData.newInstance(DataTypeEnum.DATE);

        if (!validUtil.isEmpty(o)) {
            IObject entity = requestData.newInstance(DataTypeEnum.OBJECT);
            entity.fromObject(o);

            Object antCode = null;
            String aspectName = "", returnName = "";
            switch (aspectType) {
                case BEFORE_START:
                    aspectName = BEFORE_START_RETURN;
                    returnName = CODE_BEFORE_START;
                    break;
                case AFTER_FINISHED:
                    aspectName = AFTER_FINISHED_RETURN;
                    returnName = CODE_AFTER_FINISHED;
                    break;
                default:
                    break;
            }

            if (RETURN_TRUE.equals(entity.getPropertyValue(aspectName))) {
                return true;
            }

            antCode = entity.getPropertyValue(returnName);

            if (!validUtil.isEmpty(antCode)) {
                remark.append(aspectType).append(" ").append(now.toString("yyyy-MM-dd[HH:mm:ss]"));
                ANT ant = initAnt();

                Map<String, Object[]> variables = new HashMap<>();
                ant.setVariables(variables);
                // 传入[this]
                ant.insertVariable(_THIS, _ENTITY, o);
                updateRemarks(o, remark.toString());

                isTrue = tryExecuteAnt(ant, antCode.toString());

                if (isTrue && !RETURN_TRUE.equals(entity.getPropertyValue(aspectName)) ||
                        !isTrue && !RETURN_FALSE.equals(entity.getPropertyValue(aspectName))) {
                    entity.setPropertyValue(aspectName, isTrue.toString());
                    outsiderDao.saveOrUpdate(o);
                }
            }
        }

        return isTrue;
    }

    public boolean tryExecuteAnt (ANT ant, String antCode) {
        boolean isTrue = false;

        IObject returnValue = requestData.newInstance(DataTypeEnum.OBJECT);
        returnValue.fromObject(ant.readahead(antCode));

        if (returnValue.length() == 2 && returnValue.get(0).equals(_BOOL)) {
            isTrue = (boolean) returnValue.get(1);
        }

        return isTrue;
    }

    //@Override
    public void updateRemarks(Object o, String info) throws Exception {
        IObject entity = requestData.newInstance(DataTypeEnum.OBJECT);
        entity.fromObject(o);

        IString oldRemark = requestData.newInstance(DataTypeEnum.STRING);
        oldRemark.append(entity.getPropertyValue("remarks"));
        oldRemark.readahead();
        String firstRow = oldRemark.readIStringLine().replaceAll("\\n", "").replaceAll("\\r", "")
                .replaceAll("\\t", " ").toString();

        IString remark = requestData.newInstance(DataTypeEnum.STRING);
        if (!info.equals(firstRow)) {
            remark.append(info).append("\n").append(entity.getPropertyValue("remarks"));

            if (remark.length() > MAX_REMARK_SIZE) {
                entity.setPropertyValue("remarks", remark.subString(0, MAX_REMARK_SIZE));
            } else {
                entity.setPropertyValue("remarks", remark.toString());
            }
            outsiderDao.saveOrUpdate(o);
        }
    }

}
